#include <iostream>
#include <string>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
#include "BlockQueue.hpp"

using namespace std;

const int pNum = 1;  // 生产者线程个数
const int cNum = 1;  // 消费者线程个数

template<class T>
class threadData
{
public:
    threadData(const string& name, blockqueue<T>* bq)
    :_name(name), _bq(bq)
    {}
    string _name;
    blockqueue<T>* _bq;
};

// 生产者执行线程
void* producer(void* args)
{
    threadData<int>* td = (threadData<int>*)args;
    int num = 10;
    while (true)
    {
        cout << td->_name << "线程生产出" << num << endl;
        td->_bq->push(num);
        sleep(1);
        num--;
        if (num == 0) break;
    }
    cout << td->_name << "线程退出" << endl;
    delete td;
    return nullptr;
}

// 消费者执行线程
void* consumer(void* args)
{
    threadData<int>* td = (threadData<int>*)args;
    int num = 10;
    while (true)
    {
        int tmp;
        td->_bq->pop(&tmp);
        cout << td->_name << "线程消费得到" << tmp << endl;
        sleep(3);
        num--;
        if (num == 0) break;
    }
    cout << td->_name << "线程退出" << endl;
    delete td;
    return nullptr;
}

int main()
{
    blockqueue<int> bq(2);  // 阻塞队列

    pthread_t tid[pNum + cNum];
    string ar1[pNum], ar2[cNum];
    for (int i = 0; i < pNum; ++i)
    {
        // 生产者线程
        ar1[i] = "生产者-" + to_string(i + 1);
        threadData<int>* td = new threadData<int>(ar1[i], &bq);
        pthread_create(tid + i, nullptr, producer, (void*)td);
    }
    for (int i = 0; i < cNum; ++i)
    {
        // 消费者线程
        ar2[i] = "消费者-" + to_string(i + 1);
        threadData<int>* td = new threadData<int>(ar2[i], &bq);
        pthread_create(tid + i + pNum, nullptr, consumer, (void*)td);
    }

    for (int i = 0; i < pNum + cNum; ++i)
    {
        pthread_join(tid[i], nullptr);  // 主线程阻塞等待
    }
    cout << "-主线程退出-" << endl;
    return 0;
}

// #define THREAD_NUM 3

// pthread_cond_t cond = PTHREAD_COND_INITIALIZER;  // 全局或者静态条件变量可以直接初始化
// int n = 12;

// class ThreadArg  // 通过自定义类型的方式将局部(主线程)定义的互斥锁对象传给每个新线程
// {
// public:
//     ThreadArg(const string& name, pthread_mutex_t* mtx)
//     :_mtx(mtx), _name(name)
//     {}

//     pthread_mutex_t* _mtx;
//     string _name;
// };

// void* threadRun(void* arg)
// {
//     ThreadArg* ta = (ThreadArg*)arg;
//     while (true)
//     {
//         pthread_mutex_lock(ta->_mtx);  // 即将进入临界区，进行加锁
//         pthread_cond_wait(&cond, ta->_mtx);  // 进来先阻塞等待，等待主线程发信号进行后序的步骤
//         if (n > 0)
//         {
//             usleep(rand()%1500);
//             cout << ta->_name << "线程抢到一张票啦" << n << endl;
//             n--;  // 访问修改共享资源
//             pthread_mutex_unlock(ta->_mtx);  // 解锁
//         }
//         else
//         {
//             pthread_mutex_unlock(ta->_mtx);  // 解锁 注意不满足需要到这里进行解锁
//             break;
//         } 

//         // usleep(rand() % 2000);  // 模拟执行其他任务
//     }
//     delete ta;  // 别忘了释放空间
//     cout << "-新线程" << ta->_name << "退出-" << endl;
//     return nullptr;
// }

// int main()
// {
//     pthread_mutex_t mtx;  // 定义局部锁对象
//     pthread_mutex_init(&mtx, nullptr);  // 局部锁对象需要调用初始化接口

//     srand((unsigned long)time(nullptr));
//     pthread_t tid[THREAD_NUM];
//     string ar[THREAD_NUM];
//     for (int i = 0; i < THREAD_NUM; ++i)
//     {
//         ar[i] = "thread-";
//         ar[i] += to_string(i + 1);
//         ThreadArg* ta = new ThreadArg(ar[i], &mtx);
//         pthread_create(tid + i, nullptr, threadRun, (void*)ta);
//     }

//     int num = 0;
//     while (true)
//     {
//         // pthread_cond_signal(&cond);  // 指定当前条件变量下任意线程(其不同线程发生竞争)
//         pthread_cond_broadcast(&cond);  // 或者全部 基本上3个3个一起
//         num++;
//         sleep(1);
//         if (num == 5)
//         {
//             while (pthread_cond_broadcast(&cond) > 0);  // 循环对触发条件线程发送最后的信号，使其线程退出
//             break;
//         }
//     }

//     // 主线程阻塞等待新线程
//     for (int i = 0; i < THREAD_NUM; ++i)
//     {
//         pthread_join(tid[i], nullptr);
//     }

//     pthread_mutex_destroy(&mtx);  // 对锁对象进行摧毁，释放
//     pthread_cond_destroy(&cond);  // 摧毁条件变量
//     cout << "-互斥锁和条件变量均被摧毁,主线程退出-" << endl;
//     return 0;
// }